package com.drpclub.gamebackend.common.filter;

import cn.hutool.json.JSONUtil;
import com.drpclub.gamebackend.common.config.SecurityConfiguration;
import com.drpclub.gamebackend.common.utils.JwtUtils;
import com.drpclub.gamebackend.common.utils.NetworkResult;
import com.drpclub.gamebackend.common.utils.log.RsHelper;
import com.drpclub.gamebackend.exception.MyAccessException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

import static com.drpclub.gamebackend.common.constant.Const.*;
import static com.drpclub.gamebackend.common.utils.DrpUtils.*;
import static com.drpclub.gamebackend.common.utils.SpringContextUtils.isDev;

/**
 * @author dongruipeng
 * @Descrpition
 * @date 2020year 05month07day  16:43:18
 */
@Component
public class AuthenticationFilter extends OncePerRequestFilter {

    @Value("${server.name}")
    private String servername;

    private final SecurityConfiguration seCon;

    public AuthenticationFilter(SecurityConfiguration seCon) {
        this.seCon = seCon;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        request.setAttribute ("requestTimeInMs", System.currentTimeMillis ());
        //禁用缓存
        response.setHeader ("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setCharacterEncoding ("utf8");

        if (request.getMethod ().equals ("OPTIONS")) {
            chain.doFilter (request, response);
            return;
        }

        final HttpHeaders headers = extractHttpHeaders (request);
        final int auth = checkRequestAccess (headers);
        if (auth == PASS_TOKEN) {
            chain.doFilter (request, response);
            return;
        }
        if (auth == FORBIDDEN) {
            if (checkAccessUrl (request)) {
                chain.doFilter (request, response);
                return;
            }
            final ResponseEntity<NetworkResult<Object>> error =
                    RsHelper.error (new MyAccessException (INVALID_LOGIN + request.getRequestURL ()));
            response.getWriter ().write (JSONUtil.toJsonStr (error.getBody ()));
            return;
        }

        if (checkAccessUrl (request)) {
            chain.doFilter (request, response);
            return;
        }
        String token;
        if ((token = getToken (request)) != null) {
            if (!JwtUtils.isTokenExpired (token)) {
                chain.doFilter (request, response);
                return;
            }
        }

        final ResponseEntity<NetworkResult<Object>> error =
                RsHelper.error (new MyAccessException (INVALID_TOKEN + request.getRequestURL ()));
        response.getWriter ().write (JSONUtil.toJsonStr (error.getBody ()));
    }

    private boolean checkAccessUrl(HttpServletRequest request) {
        final String uri = request.getRequestURI ();
        return verifySecurityPath (seCon.getPermitPaths (), uri);
    }

    private int checkRequestAccess(HttpHeaders headers) {
        if (isDev ()) {
            return PASS_TOKEN;
        }
        if (headers.containsKey (HttpHeaders.REFERER)) {
            final List<String> refers = headers.get (HttpHeaders.REFERER);
            if (refers != null && refers.get (0).contains (servername)) {
                return PASS_ACCESS;
            }
        }
        return FORBIDDEN;
    }
}
